<?php

// $Id: drigg.module,v 1.1.2.40 2008/09/25 01:37:17 mercmobily Exp $ 
// D6 upgrade: http://drupal.org/node/114774

// Load external include files to keep the module nice and tidy
if (function_exists('drupal_get_path')) {
  include_once(drupal_get_path('module', 'drigg') .'/config_forms.inc');
  include_once(drupal_get_path('module', 'drigg') .'/helpers.inc');
  include_once(drupal_get_path('module', 'drigg') .'/legacy_and_missing.inc');
}

#include_once dirname(__FILE__) .'/config_forms.inc';
#include_once dirname(__FILE__) .'/helpers.inc';
#include_once dirname(__FILE__) .'/legacy_and_missing.inc';

/**
 * Implementation of hook_help().
 */
function drigg_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      // This description is shown in the listing at admin/modules.
      return t('A complete Digg/Pligg clone in Drupal');
  }
}

/** 
 * Implementation of hook_menu(). 
 * 
 * This is again "the usual story". However, note that this "menu" is
 * quite tricky, because it needs to pass the right arguments to
 * drigg_node_list(). The function is commented throughout
 */ 
function drigg_menu($may_cache) { 
  $items = array(); 

  if ($may_cache) { 

   $items[] = array('path' => 'drigg/aliases_mass_recalculation',
      'title' => t('Drigg - Node alias mass-recalculation'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('drigg_aliases_mass_recalculation_confirm'),
      'access' => user_access('administer site configuration'),
      'type' => MENU_CALLBACK);


    $items[] = array(
      'path' => 'admin/settings/drigg',
      'title' => t('Drigg module'),
      'description' => t('Settings for the Drigg module'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('drigg_admin_settings'),
      'access' => user_access('administer site configuration'),
      'type' => MENU_NORMAL_ITEM);


    $items[] = array('path' => 'admin/settings/drigg/general',
      'title' => t('General'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10);

    $items[] = array(
      'path' => 'drigg/ajax/handle',
      'title' => t('Ajax handler'),
      'description' => t('Ajax handler'),
      'callback' => 'drigg_ajax_responses',
      'access' => TRUE,
      'type' => MENU_CALLBACK);

  }
  else {
    drupal_add_js(drupal_get_path('module', 'drigg') .'/drigg.js');

    drupal_add_js(array(
      'drigg' => array(
        // Get the base path:
        'base_path' => base_path()
      )
    ), 'setting');

    /* NO LONGER NEEDED. Now, rather than this ugly URL-snatcher, which
       is really quite unreliable, the drigg admin will have to allow
       anonymous posting of drigg nodes. Drigg will then stop them. */
    /*$items[] = array('path' => 'node/add/drigg',
      'title' => t('Create content'),
      'callback' => 'node_add_wrapper',
      'callback arguments' => array('drigg'),
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
      'weight' => 1);
    */

  }

  return $items; 
} 


/** 
 * Implementation of hook_node_info(). 
 */ 
function drigg_node_info() { 
  return array(
    'drigg' => array(
      'name' => t('Scoop'),
      'module' => 'drigg',
      'description' => t("Digg-style node"),
      'has_title' => TRUE,
      'title_label' => t('Scoop title'),
      'has_body' => TRUE,
      'body_label' => t('Scoop')
     )
   ); 
}   

/** 
 * Implementation of hook_perm(). 
 * 
 */ 
function drigg_perm() { 
  return array(
               'drigg ad free site', 

               'create drigg stories',
               'create-as powers in drigg', 
               'edit own drigg stories',
               'edit own promoted drigg stories',
               'edit drigg stories',
               'kill drigg stories', 
               'delete drigg stories', 
               'access drigg stories', 

               'no drigg redir for duplicate url', 
              ); 
} 

/** 
 * Implementation of hook_access(). 
 */ 
function drigg_access($op, $node) { 
  global $user; 

  // Permission to create a story
  if ($op == 'create') { 
    return user_access('create drigg stories'); 
  } 

  // Permission to delete a story
  if ($op == 'delete') { 
    return user_access('delete drigg stories'); 
  } 

  // Permission to update a story
  if ($op == 'update' ) { 
    if (user_access('edit drigg stories')) {
      return TRUE;
    }

    // Also allow editing access if the user has the right permission and
    // the story is not too old...
    elseif (user_access('edit own drigg stories') && ($user->uid == $node->uid)) {
      $delta=time() - $node->created;
      $seconds_able_to_edit=variable_get('drigg_hours_able_to_edit', '0') * 3600;
      #drupal_set_message("HERE: $delta, $seconds_able_to_edit");

      if (! $seconds_able_to_edit  ||  $delta < $seconds_able_to_edit ) {


        // Actual permission is given in two cases: either the story is not
        // promoted...
        if (!$node->promote) {
          return TRUE;
        }
        // ...or the story is promoted and the user has the ability to
        // edit promoted stories!
        if ($node->promote && user_access('edit own promoted drigg stories')) {
          return TRUE;
        }


      }
    }
    return FALSE;
  } 

  // Permission to view a story
  if ($op == 'view') { 
    if (user_access('access drigg stories')) { 
      return TRUE;
    }
  } 

  // Other than that, get stuffed!
  return FALSE;
} 



/** 
 * Implementation of hook_cron(). 
 *
 * The main purpose of this function
 *  - Run any "backgroud promotion" procedures
 *  - Assign random votes if required by the module
 */ 
function drigg_cron() {
  drigg_debug_msg("drigg's cron started!");
  #watchdog("", "Drigg's cron started!");
  $cron_timestamp = variable_get('drigg_cron_timestamp', time());
  #$cron_timestamp  = time()-(60*30);

  // ///////////////////////////////////////////////
  // Every 15 minutes...
  // ///////////////////////////////////////////////
  if ((time() - $cron_timestamp) >= 60*15  ) {
    // ...
  } 

  // Make sure the variable is set at the end of the job
  variable_set('drigg_cron_timestamp', time());
}


/**
 * Implementation of hook_db_rewrite_sql
 * 
 * This function will make absolute sure that:
 *  1) pages like term/taxonomy/8 will not return unpublished
 *     nodes
 *  2) "killed" scoops won't show unless accessed directly.
*/

function drigg_db_rewrite_sql($query, $primary_table, $primary_field, $args) {

  // This will only filter node lists
  if ($primary_table == 'n' && $primary_field == 'nid') {

    $return = array();
    $return['where'] .=  " 1=1 ";

    ///////////////////////////////////////////////////////
    // Rewrite the query that lists nodes from taxonomy, so
    // that UNPROMOTED nodes are not shown.
    // This will also affect anything (see: a box) that is being 
    // viewed while viewing, for example/ taxonomy/term/8.
    // An obvious bug, is that in taxonomy/term/8 the block
    // "upcoming stories" won't work.
    // (Yes, this is a problem, and a bad side effect. That's 
    // just life.
    ///////////////////////////////////////////////////////
    //
    if (variable_get("drigg_filter_unpublished_in_tags", TRUE)) {
      if (arg(0) == 'taxonomy' && arg(1) == 'term') {
        $return['where'] .=  " AND !(n.type='drigg' AND n.promote=0) ";
      }
    }

    // The generic case.  This will make sure that killed nodes
    // are not viewed.
    // If it's not viewing the node directly, then test
    // if the node has been killed - in which case, it
    // won't show, EVER, in any query apart from
    // direct ones. THis is perfect.
    if ( !(   arg(0)=='node' && is_numeric(arg(1)) )) {
      $return['where'] .=  " AND !(n.type='drigg' AND dn2.killed=1 ) ";
      $return['join']  .= " LEFT JOIN {drigg_node} dn2 ON dn2.dnid = n.nid ";
    }

  }   
  return $return;
}

#####################################################################
#      FUNCTIONS TO RECALCULATE THE SECTIONS CACHE
#####################################################################

/**
 * Implementation of hook_form_alter()
 * All it does is add a hook to the form "taxonomy_form_term", so that
 * if a person changes a section name, the function drigg_taxonomy_form_term()
 * is called -- which in turn recalculates the drigg_section_list.
 */
function drigg_form_alter($form_id, &$form) {

  #drupal_set_message("The form ID is $form_id"); 
  if ($form_id == 'taxonomy_form_term') {
    $form['#submit']['drigg_taxonomy_form_term'] = array();
  }
  if ($form_id == 'taxonomy_term_confirm_delete') {
    $form['#validate']['drigg_taxonomy_form_delete_check'] = array();
  }
  
  // Here we want to keep track of previous $destination variable
  if ($form_id == 'user_register' && array_key_exists('drigg_destination_login',$_SESSION) && $_SESSION['drigg_destination_login']!="") {
    $form['#action'] = "/user/register?destination=".urlencode($_SESSION['drigg_destination_login']);
    unset ($_SESSION['drigg_destination_login']);
  }
  if ($form_id == 'user_login' && array_key_exists('drigg_destination_register',$_SESSION) && $_SESSION['drigg_destination_register']!="") {
    $form['#action'] = "/user?destination=".urlencode($_SESSION['drigg_destination_register']);
    unset ($_SESSION['drigg_destination_register']);
  }
}

function drigg_taxonomy_form_term() {
    drupal_set_message("Drigg cache variable for term shortcuts reset!");
    drupal_set_message("Remember to run a mass recalculation in the drigg interface (Admin -> Settings -> Drigg Module) if you change a category name, so that you update existing nodes!");
    variable_set("drigg_section_list", drigg_section_list(TRUE));
}


function drigg_taxonomy_form_delete_check($form_id, $form_values) {

  $tid = $form_values['tid'];
  $vid = db_result(db_query("select vid from {term_data} where tid=%d", $tid));

  // Paranoid check. This is just to make sure...
  if ($vid == 0) {
    form_set_error('', t("Vocabulary for the term not found. Deletion not allowed."));
  }

  // If the vid is Drigg's, then some serious checking should happen
  if ($vid == variable_get('drigg_section_vid', 0)) {

    $how_many = db_result(db_query("SELECT count(*) FROM {term_node} tn LEFT JOIN {node} n on tn.nid = n.nid WHERE tn.tid=%d and n.type='drigg'", $tid));
    if ($how_many != 0) {
      form_set_error('', t("Sorry, deletion of this term is not allowed since there are !number scoops in the database right now. Please change those scoop's categories first.", array('!number' => $how_many)));
    }

  }
   
  #drupal_set_message("HERE: $tid, $vid, $how_many");
  
}

#####################################################################
#      END OF FUNCTIONS TO RECALCULATE THE SECTIONS CACHE
#####################################################################



#####################################################################
##         START OF MASS RECALCULATION OF DRIGG ALIASES
#####################################################################

/**
 * This is a simple confirmation step to make sure that the
 * user really wants to go ahead
 *
 * @return
 *   The confirmation form
*/
function drigg_aliases_mass_recalculation_confirm() {
  return confirm_form(
    array(),
    t('Are you sure you want to recalculate the category URL alias of every Drigg node?'),
    'admin/settings/drigg',
    t('Each node will be updated so that it has the right URL alias'),
    t('Run mass-recalcuation of category aliases'), t('Cancel')
  );
}


/**
 * At this point, the answer was confirmed. So, the recalculation
 * actually takes place
 *
 * @param $form_id
 *   The form id
 * @param $form
 *   The form
 * @return
 *   A redirection to the module's configuration screen
 */
function drigg_aliases_mass_recalculation_confirm_submit($form_id, &$form) {

  if ($form['confirm']) {
    drigg_aliases_mass_recalculation();
    drupal_set_message(t('The recalculation was done!'));
    return 'admin/settings/drigg';
  }
}

function drigg_aliases_mass_recalculation() {
  
  $query = "SELECT dn.dnid,td.name FROM {drigg_node} dn LEFT JOIN {term_node} tn ON dn.dnid=tn.nid LEFT JOIN {term_data} td ON tn.tid = td.tid WHERE td.vid=%d";

  // Go through the list of automatically votable articles
  $result = db_query($query, variable_get('drigg_section_vid', 0));
  while ($data = db_fetch_object($result)) {
     $safe_name = drigg_safe_term_name($data->name);
     db_query("UPDATE {drigg_node} SET safe_section='%s' WHERE dnid=%d", $safe_name, $data->dnid);
    
  } 
}

####################################################################
##         END OF MASS RECALCULATION OF DRIGG ALIASES
####################################################################




#################################################################
##                   NODE FORM FUNCTIONS
#################################################################

/** 
 * Implementation of hook_form(). 
 * 
 */ 
function drigg_form(&$node, &$param) { 

  global $user;


  // ***********************************************************
  // ******* CHECK THAT THE URL WASN'T ALREADy SUBMITTED *******
  // ***********************************************************

  $get_url  = drigg_clean_utf( $_GET['url'] );
  if ($get_url != '') {
    $n=drigg_url_exists($get_url);
    if ($n) {
      if ($n->status) {
        drupal_set_message(l(t('The URL has already been submitted!'),'node/'.$n->nid));
        drupal_goto('node/'.$n->nid);
      }
      else {
        drupal_set_message(t("The URL is being submitted right now!"));
        drupal_goto("");
      }
    }
  }



  // The user is "anonymous". Unless anonymous is allowed,
  // redirect to the login page
  //
  if(!$node->nid && $user->uid == 0 && ! variable_get('drigg_anonymous_can_create_entries',FALSE)){

    // The $destination variable will be indispensible, no matter what
    // Make it up
    $get_url = urlencode(drigg_clean_utf($_GET['url']));
    $get_title = urlencode(drigg_clean_utf($_GET['title']));
    $get_body  = urlencode(drigg_clean_utf($_GET['body']));
    $submit = substr(url('node/add/drigg'), 1);
    $destination = urlencode( "$submit?url=$get_url&title=$get_title&body=$get_body");

    // OK, the real story starts here. The user is NOT logged in.
    // Case 1: he's just come from the "register" page. In this case,
    // recover the drigg_destination_login variable to set $destination,
    // and send straight to the "register" page...
    $referer=referer_uri();
    if (preg_match("|user/register\?destination\=$submit|", $referer)) {
    	$_SESSION['drigg_destination_login'] = $destination;
      drupal_set_message( t("Please use your login and password to login!"));
      drupal_goto(url('user/login', NULL, NULL, TRUE), "destination=". urlencode($destination));

    // Otherwise, he's come from somewhere else that is not the "register"
    // page: give them a chance to register. However, save $destination
    // in a session variable first.
    }
    else {
			$_SESSION['drigg_destination_register'] = $destination;
      drupal_set_message(t("You need to login to submit stories! Please create your new account if you don't have one already"));
      drupal_goto(url('user/register', NULL, NULL, TRUE), "destination=". urlencode($destination));

    }
  }
  
  // Delete old session variables
	unset($_SESSION['drigg_destination_register']);
	unset($_SESSION['drigg_destination_login']);

  // If the node is new, and a variable was passed through the query string,
  // then sneak these in. BUT, if the URL had already been submitted, then
  // redirect to the story
  if (!$node->nid) {

    $get_url = drigg_clean_utf($_GET['url']);
    $get_title = drigg_clean_utf($_GET['title']);
    $get_body = drigg_clean_utf($_GET['body']);
  
    #drupal_set_message("$get_url , $get_title , $get_body ");
 
    if ($get_url != '') {
      $node->url = $get_url;
      $node->title = $get_title;
      $node->body = $get_body;
    }      
  }

  if ($node->nid) {
    $editing_var = $node->nid;
  }
  else {
    $editing_var = 0;
  }

	// Add our JavaScript variables:
	drupal_add_js(array(
		'drigg' => array(
		  'body_minimum_length' => (int)variable_get('drigg_body_minimum_length', 50),
		  'body_maximum_length' => (int)variable_get('drigg_body_maximum_length', 400),
		  'title_minimum_length' => (int)variable_get('drigg_title_minimum_length', 10),
		  'title_maximum_length' => (int)variable_get('drigg_title_maximum_length', 70),
		  'allow_empty_url' => (int)variable_get('drigg_url_mode', 0),
		  'editing_node' => $editing_var
		 )
		), 'setting'
	);

  // This is going to be used later for related links
  $title = $_POST['title'];
  $body = $_POST['body'];


  $form['taxonomy']['drigg_added'] = array(
    '#value' => t(variable_get('drigg_taxonomy_explanation', '')),
    '#weight' => variable_get('drigg_taxonomy_weight', 0),
  );

  if (user_access('create-as powers in drigg')) {

    // Work out the list of users and uids
    $uid_choices[-1] = t('YOURSELF');
    $uids = explode(',', variable_get('drigg_submit_as_users', ''));
    foreach ($uids as $uid) {
      if ($uid != '') {
        $u = user_load(array('uid' => $uid));
        $uid_choices[$uid] = $u->name;
      }
    }

    $form['submit_as'] = array(
      '#type' => 'select', 
      '#title' => t("Submit the story as..."),
      '#options' => $uid_choices,
      '#default_value' => $node->submit_as,
      '#weight' => -10, 
    );
  }

  // Mode "2" means "no URL form AT ALL". ALSO, if the URL is node/XXX, then
  // it's a NON-URL and it's therefore not editable
  if (variable_get('drigg_url_mode', 0) != 2 && substr($node->url, 0, 5) != 'node/') {
    $form['url'] = array(
      '#type' => 'textfield', 
      '#title' => t('Story\'s URL'),
      '#size' => 60,
      '#maxlength' => 255, 
      '#required' => ! variable_get('drigg_url_mode', 0), 
      '#weight' => -8, 
      '#default_value' => $node->url);
  }

  if (variable_get('drigg_trackback_enable', FALSE) &&
     variable_get('drigg_trackback_form_field', FALSE)) {

    $form['trackback_ping_url'] = array(
      '#type' => 'textfield', 
      '#title' => t('Original story\'s trackback URL (if known)'),
      '#size' => 60,
      '#maxlength' => 255, 
      '#required' => FALSE, 
      '#weight' => -8, 
      '#default_value' => $node->trackback_ping_url);
  }


  $form['title'] = array(
    '#type' => 'textfield', 
    '#title' => t('Story\'s title'),  
    '#size' => 60,
    '#maxlength' => variable_get('drigg_title_maximum_length', 70) + 10, 
    '#required' => TRUE, 
    '#weight' => -7, 
    '#default_value' => $node->title);
 
  $form['body'] = array(
    '#type' => 'textarea',
    '#title' => t('Story\'s description'), 
    '#default_value' => $node->body,
    '#weight' => -6, 
    '#required' => FALSE ); 

  $form['body_format_options']=array(
    '#value' => t( variable_get('drigg_body_formatting_options', '')),
    '#weight' => -6, 
  );

  /*$form['format'] = array(
    '#type' => 'hidden',
    '#default_value' => variable_get('drigg_format_id',''),
  );*/
  
  $form['format'] = array(
    '#type' => 'value',
    '#value' => variable_get('drigg_format_id', 0),
  );

  #drupal_set_message("TITLE: $title");
  #drupal_set_message("BODY : $body");

  #if (!$node->nid && $title != '' && $body != '') {
 
  if (module_exists('drigg_rl')) {
    if (!$node->nid) {
      if ($title != '' && $body != '') {
        $form['similar'] = array(
          '#value' => '<div id="related_links_box">'.
            drigg_rl_related_links_get_html(
            $title .' '. $body,
            NULL,
            variable_get('drigg_rl_how_many_in_submit_form', '10'), 
            variable_get('drigg_rl_teasers_in_submit_form', TRUE) 
            ) .'</div>' 
        );
      }
      else {
        $form['similar']=array(
          '#value' => '<div id="related_links_box"></div>'
        );
      }
    }
  }

  if ($node->nid && user_access('kill drigg stories')) {
    $form['killed'] = array(
      '#type' => 'checkbox',
      '#title' => t('Killed'), 
      '#description' => t('The story is only accessible if linked to directly'),
      '#default_value' => $node->killed,
      '#weight' => -5, 
      '#required' => FALSE
    ); 
  }

  if ($node->title_url) {
    $form['not_a_field'] = array(
     '#value' => t('Path to be used: ') . $node->title_url);
  }

  return $form; 
} 

/** 
 * Implementation of hook_validate(). 
 */ 
function drigg_validate(&$node) { 

  global $drigg_trackback_ping_url;
  global $drigg_content_type;
  global $user;

  #if ($user->uid != 0) drupal_set_message("HERE: ". $node->format);
 
  // It's cuter this way
  $allow_empty_url = variable_get('drigg_url_mode', 0);
  drigg_debug_msg("Variable \$allow_empty_url is: $allow_empty_url");

  // Check the story URL, if it's not empty. Note: an empty URL doesn't
  // get a chance to be valid
  drigg_debug_msg("Checking the URL...");
  $url_valid = FALSE;
  if ($node->url != '') {
    if (drigg_url_valid($node->url)) {
      $url_valid = TRUE;
      drigg_debug_msg("The URL is valid!");
    }
    else {
      form_set_error('url', t('The URL is not valid'));
    }
  }
  else {
    drigg_debug_msg("The URL is empty. Therefore, it cannot be valid.");
  }

  // Sometimes, the URL cannot be empty
  if ($node->url == '' && ! $allow_empty_url ) {
    form_set_error('url', t('The URL cannot be empty'));
    drigg_debug_msg("Empty URL not allowed");
  }

  if ($node->submit_as != 0 && $node->submit_as != -1 && !user_access('create-as powers in drigg')) {
    form_set_error('', t('You are not allowed to submit-as anybody'));
  }

  if( $user->uid == 0 && ! variable_get('drigg_anonymous_can_create_entries',FALSE)){
    form_set_error('', t('Anonymous posting of Drigg nodes is now allowed'));
  }

  // #########################################################
  // ################ TRACKBACK START ########################
  // #########################################################

  // Check that the trackback ping url is valid
  if (variable_get('drigg_trackback_enable', TRUE)) {
    drigg_debug_msg("Trackback is enabled!");
    $trackback_ping_url_valid = FALSE;
    // Check the trackback URL, if it's not empty
    if ($node->trackback_ping_url != '') {
      drigg_debug_msg("Trackback URL given in the form...");
      if (drigg_url_valid($node->trackback_ping_url)) {
        $trackback_ping_url_valid = TRUE;
        drigg_debug_msg("...and valid. Setting \$trackback_ping_url_valid to 1");
      }
      else {
        form_set_error('trackback_ping_url', t('The trackback URL is not valid'));
        drigg_debug_msg("...and NOT valid.  \$trackback_ping_url_valid is FALSE");
      }
    }
  }

  //////////////////////////////////////////////////////////
  // If the trackback ping url is empty, and if an URL
  // was actually passed, try to fill the trackback URL out
  //////////////////////////////////////////////////////////
  if ( variable_get('drigg_trackback_enable', FALSE) &&
      variable_get('drigg_trackback_autodiscovery', FALSE) && 
      $node->url != '' ) {

    drigg_debug_msg("Trackback with autodiscovery is active, and we have an URL");

    // Trackback URL not provided. Try to work it out

    if ($node->trackback_ping_url=='' ) {
      drigg_debug_msg("The trackback ping URL is empty. Starting discovery");

      // Fetch the URL (!)
      $url_request = drigg_url_http_ok($node->url, 'GET', TRUE);
      #$url_request = TRUE;
      $http_request_attempted = TRUE;
      drigg_debug_msg("HTTP request made to the URL");

      // CASE #1: IT WORKED. TRY and set $node->trackback_ping_url...
      if ($url_request) {
        $http_request_url_worked = TRUE;
        drigg_debug_msg("The request WORKED!");

        // Look for the trackback URL
        if (preg_match('/.*<rdf:RDF.*trackback:ping="([^"]+)".*<\/rdf:RDF>.*/s', $url_request->data, $matches) || preg_match('#<link rel="pingback" href="([^"]+)" ?/?>#', $url_request->data, $matches)) {
          $node->trackback_ping_url = $matches[1];
          drigg_debug_msg("Trackback ping found: ". $node->trackback_ping_url);
        }
        else {
          drigg_debug_msg("Trackback ping NOT found in");
        }
        $node->content_type = $url_request->headers['Content-Type'];
        drigg_debug_msg("node->content_type:". $node->content_type);

        // JUST IN CASE, if the trackback_ping_url is NOT valid, delete it
        if ($node->trackback_ping_url && !drigg_url_valid($node->trackback_ping_url)) {
          #drupal_set_message("The trackback ping URL was NOT valid");
          $node->trackback_ping_url = '';
          drigg_debug_msg("WAIT! The trackback ping was NOT valid - deleted!");
        }

      // CASE #2: IT DIDN'T WORK
      }
      else {
      	if (variable_get('drigg_url_validate', TRUE)) {
          $http_request_url_worked = FALSE;
        } else {
        	// No Http URL Validation, we force it to true
        	$http_request_url_worked = TRUE;
        }
     }

    // A user added a trackback straight into the form. CHECK that the
    // trackback URL is actually valid and it works HTTP-wise
    }
    else {

      drigg_debug_msg("The trackback was given by the user. Checking it");
      if ($trackback_ping_url_valid) {
        drigg_debug_msg("The trackback URL given by the user was valid...");
        if (variable_get('drigg_url_validate', TRUE) && !drigg_url_http_ok($node->trackback_ping_url)) {
          form_set_error('trackback_ping_url', t("The trackback ping URL doesn't seem to be working!"));
          drigg_debug_msg("The trackback URL given by the user did NOT work");
        }
      }
    }
  }
  // #########################################################
  // ################ TRACKBACK END   ########################
  // #########################################################

  // At this point, it's still possible tht the HTTP request wasn't attempted, 
  // because the user had already supplied the trackback or because trackback 
  // autodiscovery was off
  // So, try to fetch the URL (just the headers...), AND at the same time
  // try to get the content_type (which will be used by hook_submit() )
  if (!$http_request_attempted && $url_valid ) {

    drigg_debug_msg("No HTTP request was attempted, but the URL was valid. Doing the 'normal' checks.");

    drigg_debug_msg("Making the HTTP request");
    $url_request = drigg_url_http_ok($node->url);
    $http_request_attempted = TRUE;
    if ($url_request) {
      drigg_debug_msg("The HTTP request WORKED!");
      $http_request_url_worked = TRUE;
      $node->content_type = $url_request->headers['Content-Type'];
      drigg_debug_msg("Content type: ". $node->content_type);
    }
    else {
    	if (variable_get('drigg_url_validate', TRUE)) {
        $http_request_url_worked = FALSE;
        drupal_set_message("Request didn't work");
      } else {
      	$http_request_url_worked = TRUE;
      }
    }
  }

  // This is to pass the new variables on 
  // to hook_update() or hook_insert(). It's ugly, but global variables
  // are the way to communicate in this case...

  drigg_debug_msg("Variable 'trackback_ping_url' is: ". $node->trackback_ping_url);
  drigg_debug_msg("Variable 'content_type' is: ". $node->content_type);
  $drigg_trackback_ping_url = $node->trackback_ping_url;
  $drigg_content_type = $node->content_type;

  // At this point, the only way to come out of this is that
  // **EITHER** the url is empty, and it's allowed...
  drigg_debug_msg("Doing the actual URL check");
  if ($allow_empty_url && $node->url == '') {
    drigg_debug_msg("Check skipped, URL empty (and allowed to be)");

  // **OR** that $http_request_url_worked is not set. This variable is
  // set either from the trackback attempt, or with an explicit check
  }
  elseif (!$http_request_url_worked) {
    drigg_debug_msg("PROBLEM: the URL was there and it DIDN'T work");
    form_set_error('url', t("The url doesn't seem to be working!"));
  }
  else {
    drigg_debug_msg("All good, the URL was there AND it worked!");
  }
 
  // Check for duplicate URLs
  if ($node->url !== '') {
    $n = drigg_url_exists($node->url, $node->nid);
    #if ($n && ! $node->nid) {
    if ($n) {

      if (!$n->status) {
         form_set_error('url', t('The URL is being submitted right now!'));
      }
      else {

        if ( user_access('no drigg redir for duplicate url')) {
          form_set_error('url', l(t('The URL has already been submitted!'),'node/'.$n->nid));
          #drupal_goto('node/add/drigg');
        }
        else {
          drupal_set_message(t("The URL has already been submitted!"));
          drupal_goto('node/'.$n->nid);
        }

      }

    }
  }

  $disallowed_section = variable_get('drigg_disallowed_term_id', '0');
  if ($disallowed_section != 0) {
    $picked_section = $node->taxonomy[variable_get('drigg_section_vid', 0)];
    if ($picked_section == $disallowed_section) {
      form_set_error('taxonomy-1', t("Please pick a section!"));
    }
  }

  #foreach ($node->taxonomy as $k => $v) {
  #  drupal_set_message("$k => $v");
  #}

  // Work out the list of users and uids
  $uids = explode(',', variable_get('drigg_submit_as_users', ''));
   
  if (user_access('create-as powers in drigg') && !in_array($node->submit_as, $uids) && $node->submit_as != -1) {
    form_set_error('submit_as', t("The user selected is not in the 'create-as' user list"));
  }

  // Check the length of the title and the body
  //
  if (variable_get('drigg_body_minimum_length', 50) != 0 && strlen(strip_tags(trim($node->body))) < variable_get('drigg_body_minimum_length', 50)) {
    form_set_error('body', t('The description is too short!'));
  }
  if (variable_get('drigg_body_maximum_length', 400) != 0 && strlen(strip_tags($node->body)) > variable_get('drigg_body_maximum_length', 400)) {
    form_set_error('body', t('The description is too long!'));
  }

  if (variable_get('drigg_title_minimum_length', 10) != 0 && strlen(strip_tags(trim($node->title))) < variable_get('drigg_title_minimum_length', 10)) {
    form_set_error('title', t('The title is too short!'));
  }
  if (variable_get('drigg_title_maximum_length', 70) != 0 && strlen(strip_tags($node->title)) > variable_get('drigg_title_maximum_length', 70)) {
    form_set_error('title', t('The title is too long!'));
  }

  if (drigg_url_banned($node->url)) {
    form_set_error('url', t('The URL is banned!'));
  }

} 

/**
 * Implementation of hook_insert
 *
 * This is just a stub to the the real function, to prevent
 * repetition of code
 */
function drigg_insert($node) {
  drigg_insert_or_update($node, "insert");
}

/**
 * Implementation of hook_update
 *
 * This is just a stub to the the real function, to prevent
 * repetition of code
 */
function drigg_update($node) {
  drigg_insert_or_update($node, "update");
}

function drigg_send_trackback_ping($url, $nid) {

  drigg_debug_msg("SENDING PING TO $url");
  // Set the parameters
  $params_url = url('node/'. $nid, NULL, NULL, TRUE);
  $site_name = variable_get('drigg_trackback_ping_blog_name', '');
  $params = array(
    'title' => variable_get('drigg_trackback_ping_title', ''),
    'excerpt' => truncate_utf8(trim(  
      t( variable_get('drigg_trackback_ping_excerpt', ''), array(
        '!url' => $params_url,
        '!site_name' => $site_name,
      ))
    ), 255),
    'blog_name' => $site_name,
    'url' => $params_url
  );

  // Make up the query
  $query = array();
  foreach ($params as $key => $value) {
    $query[] = $key .'='. urlencode($value);
  }
  $query = implode('&', $query);

  #drupal_set_message("Query: $query");

  // Actually send the requet!
  $reply = drupal_http_request($url, array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'), 'POST', $query);
  $succ = 0;
  if (!$reply->error && preg_match('|<error>([0-9]+)</error>|', $reply->data, $match)) {
    $succ = $match[1] ? 0 : 1;
  }

  drigg_debug_msg("TB: Returning: $succ");
  drigg_debug_msg("TB: Reply data: ". $reply->data);
  drigg_debug_msg("TB: Query: ". $query);

  // That's it :-D
  return $succ;
}

/**
 * Does the actual insert/update into the database.
 * NOTE: revisions are not considered here, no matter what. This is a
 * design decision: the module keeps track of the publishing info of the
 * node as a _whole_.
 * Some trickery happens here. 
 * The variable $node->submit_as might be set,
 * in which case the node's author is forced to somebody else (the change is
 * applied to the node and to its revision)
 * 
 * @param $node
 *   The node to add/update
 * @param $op
 *   It can be 'insert' or 'update'
 * @return
 *   Nothing
*/
function drigg_insert_or_update($node, $op) {

  global $drigg_trackback_ping_url;
  global $drigg_content_type;

  global $user;

  // First of all, clear the URL cache. We don't want this to pollute
  // the database
  $_SESSION['drigg_request_cache'] = array();


  $node->trackback_ping_url = $drigg_trackback_ping_url;
  $node->content_type = $drigg_content_type;

  #drupal_set_message("SUBMIT Content type: ". $node->content_type);
  #drupal_set_message("SUBMIT Trackback ping URL: ". $node->trackback_ping_url);

  // Work out what the requested category is in "safe" terms (set
  // the "safe_category" variable
  //
  $v = variable_get('drigg_section_vid', 0); 
  $tl = drigg_section_list();
  $t = $node->taxonomy[$v];
  $safe_section = $tl['lookup'][$t]['safe_name'];
  #drupal_set_message("t is $t");
  #drupal_set_message("safe_section is $safe_section");

  // Makes absolute sure that nothing gets the "promote" flag
  // without a valid "promoted_on" amount
  //
  // CHANGED: never allow promoted_on=0, because it never actually
  // makes sense. FIXME: check that this is actually good now
  //if($node->promoted_on == 0 && $node->promote == 1){
  if ($node->promoted_on == 0) {
    $node->promoted_on = time();
  }

  // $node->url CAN be blank in Drigg now. If that happens, it
  // NEEDS to be given a unique URL - node/XXX is the best option,
  // since it will work with l()
  if ($node->url == '') {
    $node->url = 'node/'. $node->nid;
  }

  if ($op == "insert" ) {

    // Work out the title URL
    $title_url = drigg_get_title_url($node->title);
    $title_url_attempt = $title_url;

    // Work out who to vote as. This will be used later
    // to set who the vote was cast by
    if ($node->submit_as != 0 && $node->submit_as != -1 ){ 

      // Fetch the user
      $account_voter = user_load(array('uid' => $node->submit_as));
      if (!$account_voter) {
        $account_voter = $user;
      }

    }
    else {
      $account_voter = $user;
    }
   
    // The insert assums that if the trackback ping is set, then
    // the trackback will work. A last-minute DB call will take care
    // of reverting it
    if ($node->trackback_ping_url === '') {
      $trackback_ping_successful = 0;
    }
    else {
      $trackback_ping_successful = 1;
    }

    $i = 0;
    while (TRUE) {


      // Try to add the story
      $result = db_query("INSERT INTO {drigg_node} (dnid, promoted_on, killed, url, title_url, safe_section, content_type, trackback_ping_url, trackback_ping_successful) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $node->nid, $node->promoted_on, $node->killed, $node->url, $title_url_attempt, $safe_section, $node->content_type, $node->trackback_ping_url, $trackback_ping_successful);

      // It worked - escape the evil while cycle
      if ($result) {

        // *** This section of code is known to conflict with CCK Imagefield ***
        if (variable_get('drigg_auto_first_vote', TRUE)) {
          // Add the first vote, according to the range.
          list($content_type, $value_type, $tag, $tmp) = drigg_votingapi_variables();
          // Give the actual vote using the Voting API - thanks Eaton!
          $v = new stdClass();
          $v->value = 1;
          $v->value_type = $value_type;
          $v->tag = $tag;
          votingapi_set_vote($content_type, $node->nid, $v, $account_voter->uid);
        }
        // *** End of code known to conflict with CCK Imagefield ***

        // Do the trackback ping, IF the functionality is enabled
        if (variable_get('drigg_trackback_enable', FALSE) && 
          $node->trackback_ping_url != '') {
          $res = drigg_send_trackback_ping($node->trackback_ping_url, $node->nid);

          // At this point, the node has already been written. So, IF the ping
          // wasn't successful, the record needs to be updated
          if (!$res) {
            db_query("UPDATE {drigg_node} SET trackback_ping_successful = 0 WHERE dnid = %d", $node->nid); 
          }

        }

        break;

      }

      // At this point, something has definitely gone wrong since
      // the insert has failed. So, this part sets the stage for
      // the next iteraction
      $title_url_attempt = $title_url .'-R'. rand(1, 20000);
      #drupal_set_message("ATTEMPT: $title_url_attempt");

      // Check that this hasn't been tried too many times. IF it has,
      // it's NASTY. MAYBE LATER: delete the node completely?
      $i++;
      if ($i == 1000) {
        drupal_set_message(t("FATAL ERROR: couldn't find a free URL for ") . $node->title, 'error');
        drupal_goto('/');
        break;
      }

    }  // End of the while(true) statement 

  }
  elseif ($op == "update") {

    db_query("UPDATE {drigg_node} SET promoted_on = %d, killed = %d, url = '%s', safe_section = '%s', content_type = '%s', trackback_ping_url = '%s', trackback_ping_successful = %d WHERE dnid = %d", $node->promoted_on, $node->killed, $node->url, $safe_section, $node->content_type, $node->trackback_ping_url, $node->trackback_ping_successful, $node->nid); 
  }  

  // If requested, change the author of that scoop
  if ($node->submit_as != 0 && $node->submit_as != -1 && user_access('create-as powers in drigg')) {
    db_query("UPDATE {node} SET uid=%d WHERE vid = %d", $node->submit_as, $node->vid);
    db_query("UPDATE {node_revisions} SET uid=%d WHERE vid = %d", $node->submit_as, $node->vid);
  }

  // Force the file format for that revision
  #db_query("UPDATE {node_revisions} SET format=%d WHERE vid = %d", variable_get('drigg_format_id', '0'), $node->vid);

}

/**
 * Support function for drigg_insert_or_update(). It tries to
 * find a free title URL, trying safe_title-1, safe_title-2, and so
 * on
 *
 * @param $title
 *   The article's title
 * @return
 *   The URL title
*/
function drigg_get_title_url($title) {

  $title_url = drigg_pathauto_cleanstring($title, variable_get('drigg_separator_short_urls', ''), TRUE);
  $title_url_attempt = $title_url;
  $i = 1;
  while (TRUE) {

    // Check that the name is free. If it is, return it. If it's not,
    // create a new string for the next attempt
    $sql = "SELECT COUNT(title_url) FROM {drigg_node} WHERE title_url='%s'";
    $result = db_result(db_query($sql, $title_url_attempt));
    #drupal_set_message("Result: $result, query: $sql, title: $title_url_attempt");
    if (!$result) {
      return $title_url_attempt;
    }
    else {
      $title_url_attempt = $title_url ."-". $i;
    }

    // Increase the counter, and "freak out" after 30 attempts
    $i++;
    if ($i == 2500) {
      drupal_set_message(t("ERROR: couldn't find a free URL for ") . $title);
      // THis will fail, but hey...
      return $title_url;
    }
  }  // End of the while(true) statement 

}

/** 
 * Implementation of hook_delete(). 
 * 
 * When a node is deleted, we need to clean up related tables. 
 */ 
function drigg_delete($node) { 
  db_query('DELETE FROM {drigg_node} WHERE dnid = %d', $node->nid); 
} 

/** 
 * Implementation of hook_load(). 
 * 
 */ 
function drigg_load($node) { 

  $additions = db_fetch_object(db_query('SELECT promoted_on, killed, url, title_url, safe_section, content_type FROM {drigg_node} WHERE dnid = %d', $node->nid)); 

  return $additions; 
} 

/** 
 * Implementation of hook_view(). 
 * 
 * This is a typical implementation that simply runs the node text through 
 * the output filters. 
 */ 
function drigg_view(&$node, $teaser = FALSE, $page = FALSE) { 
  global $user;

  // Prepare the node for displaying...
  $node = node_prepare($node, $teaser); 

  return $node;
}

################################################################
##               END OF  NODE FORM FUNCTIONS
################################################################



################################################################
##                 AJAX-RELATED FUNCTIONS
################################################################

/**
 * Ajax responder.
 * This function doesn't really have any function-parameters. However,
 * it reads the $_REQUEST array, to find the variables 'operation' and 'p1'.
 * 'operation' can be:
 *   - related_links
 *   - validate_url
 * Note that the 'exit' callback of every module is called.
*/
function drigg_ajax_responses() {

  if ($_REQUEST['operation']) {

    // Set the incoming variables
    $operation = $_REQUEST['operation'];

    // VALIDATE URL FUNCTION
    //
    if ($operation == 'validate_url') {

      $url          = $_REQUEST['url'];
      $editing_node = $_REQUEST['editing_node'];

      $n = drigg_url_exists($url, $editing_node);
      if ($n) {
        if ($n->status) {
          $error = l(t('The URL has already been submitted!'),'node/'.$n->nid);
        }
        else {
          $error = t('The URL is being submitted right now!');
        }
      }

      if (!drigg_url_valid($url)) {
        $error = t('The URL is not valid');
      }

      if (drigg_url_banned($url)) {
        $error = t('The URL is banned!');
      }

      if (variable_get('drigg_url_validate', TRUE) && !drigg_url_http_ok($url, 'HEAD', FALSE)) {
        $error = t('The URL is not functioning!');
      }

      // Return the right thing to the javascript
      if ($error != '') {
        print $error;
        #drupal_set_message($error);
      }
      else {
        print 'success';
      }

      module_invoke_all('exit');
      exit;
    }

  }

  // Just in case...
  print "NOOP. You're a human, aren't you?";
  module_invoke_all('exit');
  exit;
}

// vim: set ft=php ts=2 sw=2 et :
